﻿using AppManager.IDAL;
using AppManager.Model;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Runtime.Remoting.Messaging;
using System.Transactions;

namespace AppManager.DAL
{
    public class BaseRepository<T> : IBaseRepository<T> where T : BaseModel
    {
        protected AppManagerDb nContext = AppManagerDb.Current;
        public T Add(T entity)
        {
            nContext.Entry<T>(entity).State = System.Data.Entity.EntityState.Added;
            nContext.SaveChanges();
            return entity;
        }

        public int Count(Expression<Func<T, bool>> predicate)
        {
            return nContext.Set<T>().Count(predicate);
        }               

        public bool Exist(Expression<Func<T, bool>> anyLambda)
        {
            return nContext.Set<T>().Any(anyLambda);
        }

        public T Find(Expression<Func<T, bool>> whereLambda)
        {
            T _entity = nContext.Set<T>().FirstOrDefault<T>(whereLambda);
            return _entity;
        }

        public IQueryable<T> FindList<S>(Expression<Func<T, bool>> whereLamdba, bool isAsc, Expression<Func<T, S>> orderLamdba)
        {
            var _list = nContext.Set<T>().Where<T>(whereLamdba);
            if (isAsc) _list = _list.OrderBy<T,
            S>(orderLamdba);
            else _list = _list.OrderByDescending<T,
            S>(orderLamdba);
            return _list;
        }

        public IQueryable<T> FindPageList<S>(int pageIndex, int pageSize, out int totalRecord, Expression<Func<T, bool>> whereLamdba, bool isAsc, Expression<Func<T, S>> orderLamdba)
        {
            var _list = nContext.Set<T>().Where<T>(whereLamdba);
            totalRecord = _list.Count();
            if (isAsc) _list = _list.OrderBy<T,
            S>(orderLamdba).Skip<T>((pageIndex - 1) * pageSize).Take<T>(pageSize);
            else _list = _list.OrderByDescending<T,
            S>(orderLamdba).Skip<T>((pageIndex - 1) * pageSize).Take<T>(pageSize);
            return _list;
        }
        #region
        public static BaseRepository<T> Current
        {
            get
            {
                var m = CallContext.GetData("basedal") as BaseRepository<T>;
                if (m == null)
                {
                    m = new BaseRepository<T>();
                    CallContext.SetData("basedal", m);
                }
                return m;
            }
        }

        public TransactionScope GetTransaction()
        {
            TransactionOptions option = new TransactionOptions()
            {
                IsolationLevel = IsolationLevel.ReadCommitted,
                Timeout = TimeSpan.FromSeconds(60),
            };

            //使用該屬性表示嵌套事務中不創建新的事務，也就是在所有嵌套的方法中所有的操作在一個事務中
            return new TransactionScope(TransactionScopeOption.Required, option);
        }


        protected AppManagerDb db = AppManagerDb.Current;
        protected DbSet<T> dbSet;
        public BaseRepository()
        {
            dbSet = db.Set<T>();
        }

        public virtual int Insert(T model)
        {
            dbSet.Add(model);
            model.CreateDate = DateTime.Now;

            return db.SaveChanges();
        }
        public virtual int Delete(T model)
        {
            nContext.Set<T>().Attach(model);
            nContext.Entry<T>(model).State = System.Data.Entity.EntityState.Modified;
            return nContext.SaveChanges();

            //T entityToDelete = dbSet.Find(col);
            //if (entityToDelete != null)
            //    dbSet.Remove(entityToDelete);
            //return db.SaveChanges();
        }

        public virtual int Delete(Expression<Func<T, bool>> predicate)
        {
            T entityToDelete = GetModel(predicate);
            if (entityToDelete != null)
                dbSet.Remove(entityToDelete);
            return db.SaveChanges();
        }
        public virtual int Update(T entityToUpdate)
        {
            using (var newdb = AppManagerDb.NewInstance)
            {
                entityToUpdate.UpdateDate = DateTime.Now;

                newdb.Entry(entityToUpdate).State = EntityState.Modified;
                return newdb.SaveChanges();
            }
        }

        public int AddOrUpdate(T model)
        {
            if (model.Id > 0)
            {
                return Update(model);
            }
            else
            {
                return Insert(model);
            }
        }

        /// <summary>
        /// 局部更新
        /// </summary>
        /// <param name="propertyExpression"></param>
        /// <param name="entities"></param>
        /// <returns></returns>
        public int UpdateIgnore(Expression<Func<T, object>> propertyExpression, params T[] entities)
        {
            return db.UpdateIgnore(propertyExpression, entities);
        }


        /// <summary>
        /// 實現對像部分屬性的更新，newModel必須時匿名對象
        /// </summary>
        /// <param name="originalEntity"></param>
        /// <param name="newEntity">newModel必須時匿名對象（這樣是為了保證不加入多餘的屬性）</param>
        /// <returns></returns>
        public int Update(T originalEntity, object newEntity)
        {
            var entry = db.Entry(originalEntity);
            if (entry.State != EntityState.Unchanged)
                entry.State = EntityState.Unchanged;
            entry.CurrentValues.SetValues(newEntity);
            return db.SaveChanges();
        }
        public virtual void InsertAll(IEnumerable<T> list)
        {
            foreach (var item in list)
            {
                item.CreateDate = DateTime.Now;
            }
            dbSet.AddRange(list);
            db.SaveChanges();
        }
        public virtual void UpdateList(IEnumerable<T> list)
        {
            using (var newDb = AppManagerDb.NewInstance)
            {
                foreach (var item in list)
                {
                    item.UpdateDate = DateTime.Now;
                    newDb.Entry(item).State = EntityState.Modified;
                }
                newDb.SaveChanges();
            }
        }
        public virtual void DeleteList(IEnumerable<T> list)
        {
            dbSet.RemoveRange(list);
            db.SaveChanges();
        }
        public virtual void DeleteList(Expression<Func<T, bool>> predicate = null)
        {

            var list = GetList(predicate);
            dbSet.RemoveRange(list);
            db.SaveChanges();
        }
        public T GetModel(Expression<Func<T, bool>> predicate = null)
        {
            return dbSet.FirstOrDefault(predicate);
        }

        /// <summary>
        /// 如果查询为空，直接返回异常
        /// </summary>
        /// <param name="predicate"></param>
        /// <param name="notrack"></param>
        /// <returns></returns>
        public virtual IEnumerable<T> GetList(Expression<Func<T, bool>> predicate = null, bool notrack = false)
        {

            IEnumerable<T> list;
            if (predicate != null)
            {
                if (notrack)
                {
                    list = dbSet.Where(predicate).AsNoTracking().ToList().AsQueryable();
                }
                else {
                    list = dbSet.Where(predicate).ToList();
                }
            }
            else {
                list = dbSet.ToList();
            }

            if (list == null)
                throw new Exception("db null error");
            return list;
        }
        #endregion
    }
}
